﻿
// **************************************************************************
//    Class Created by Mick Doherty (Dotnetrix) June 2010
//    http://dotnetrix.co.uk/
//
//    ...for GlassUI (an AeroGlass UI Library)
//    http://glassui.codeplex.com/
// **************************************************************************

using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Windows.Forms;

namespace GlassUI
{
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Lite")]
    public abstract class LiteControlBase
    {
        protected LiteControlBase(GlassControlBase parent)
            : base()
        {
            this.owner = parent;
            // Attach ourself to the Parents Mouse Events
            this.owner.MouseEnter += new EventHandler(owner_MouseEnter);
            this.owner.MouseLeave += new EventHandler(owner_MouseLeave);
            this.owner.MouseDown += new MouseEventHandler(owner_MouseDown);
            this.owner.MouseUp += new MouseEventHandler(owner_MouseUp);
            this.owner.MouseMove += new MouseEventHandler(owner_MouseMove);
            this.owner.EnabledChanged += new EventHandler(owner_EnabledChanged);
        }

        void owner_MouseEnter(object sender, EventArgs e)
        {
            if (this.Bounds.Contains(this.owner.PointToClient(Cursor.Position)))
            {
                this.OnMouseEnter(e);
            }
        }

        void owner_MouseLeave(object sender, EventArgs e)
        {
            this.OnMouseLeave(e);
        }

        void owner_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.Bounds.Contains(e.Location))
            {
                this.mousePressed = true;
                this.OnMouseDown(e);
            }
        }

        void owner_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.Bounds.Contains(e.Location))
            {
                if (!this.mouseIn)
                {
                    this.OnMouseEnter(e);
                }
                this.OnMouseMove(e);
            }
            else
                this.OnMouseLeave(e);
        }

        void owner_MouseUp(object sender, MouseEventArgs e)
        {
            if (this.mousePressed)
            {
                this.OnMouseUp(e);
                this.mousePressed = false;
            }
        }

        void owner_EnabledChanged(object sender, EventArgs e)
        {
            this.Enabled = owner.Enabled;
        }

        #region Event Declarations

        public event EventHandler EnabledChanged;
        public event EventHandler LocationChanged;
        public event EventHandler SizeChanged;
        public event EventHandler StateChanged;

        public event EventHandler MouseEnter;
        public event EventHandler MouseLeave;
        public event MouseEventHandler MouseDown;
        public event MouseEventHandler MouseUp;
        public event MouseEventHandler MouseMove;

        #endregion

        #region Private instance variables

        internal GlassControlBase owner;
        private bool mousePressed;
        private bool mouseIn;
        private bool focused;

        private bool enabled = true;
        private Point location;
        private Size size = new Size(50, 50);
        private ControlState state = ControlState.Normal;
        private String name = String.Empty;

        #endregion

        #region Property Declarations

        //Bottom
        [Browsable(false)]
        public int Bottom
        {
            get { return this.Top + this.Height; }
        }

        //Bounds
        [Browsable(false)]
        public Rectangle Bounds
        {
            get { return new Rectangle(this.Location, this.Size); }
        }

        //Enabled
        [DefaultValue(true)]
        public virtual bool Enabled
        {
            get { return enabled; }
            set
            {
                if (enabled != value)
                {
                    enabled = value;
                    OnEnabledChanged(EventArgs.Empty);
                }
            }
        }

        //Height
        [Browsable(false)]
        public int Height
        {
            get { return this.Size.Height; }
        }

        //Left
        [Browsable(false)]
        public int Left
        {
            get { return this.Location.X; }
        }

        //Location
        [Category("Layout"), DefaultValue(typeof(Point), "0,0")]
        public virtual Point Location
        {
            get { return location; }
            set
            {
                if (!location.Equals(value))
                {
                    location = value;
                    OnLocationChanged(EventArgs.Empty);
                }
            }
        }

        //Name
        [Browsable(false)]
        [ParenthesizePropertyName(true)]
        public virtual String Name
        {
            get
            { return name; }
            set { name = value; }
        }

        //Right
        [Browsable(false)]
        public int Right
        {
            get { return this.Left + this.Width; }
        }

        //Size
        [Category("Layout"), DefaultValue(typeof(Size), "50,50")]
        public virtual Size Size
        {
            get { return size; }
            set
            {
                if (!size.Equals(value))
                {
                    size = value;
                    OnSizeChanged(EventArgs.Empty);
                }
            }
        }

        //State
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        internal ControlState State
        {
            get { return this.state; }
            set
            {
                if (state == value)
                    return;
                state = value;
                this.OnStateChanged(EventArgs.Empty);
            }
        }

        //Top
        [Browsable(false)]
        public int Top
        {
            get { return this.Location.Y; }
        }

        //Width
        [Browsable(false)]
        public int Width
        {
            get { return this.Size.Width; }
        }

        //Focused
        [Browsable(false)]
        public bool Focused
        {
            get { return this.focused; }
        }

        #endregion

        #region Internal methods

        internal void ChangeFocus(bool focus)
        {
            if (this.Enabled)
            {
                this.focused = focus;
                if (focus)
                    this.State = ControlState.Focused;
                else
                    this.State = ControlState.Normal;
            }
        }

        #endregion

        #region Protected Methods

        protected virtual void OnEnabledChanged(EventArgs e)
        {
            this.State = this.Enabled ? ControlState.Normal : ControlState.Disabled;
            if (this.EnabledChanged != null)
                this.EnabledChanged(this, e);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnSizeChanged(EventArgs e)
        {
            if (this.SizeChanged != null)
                this.SizeChanged(this, e);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnLocationChanged(EventArgs e)
        {
            if (this.LocationChanged != null)
                this.LocationChanged(this, e);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnStateChanged(EventArgs e)
        {
            this.owner.Invalidate(this.Bounds);
            if (this.StateChanged != null)
                this.StateChanged(this, e);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnMouseEnter(EventArgs e)
        {
            if (this.Enabled)
            {
                this.mouseIn = true;
                this.State = Control.MouseButtons == MouseButtons.None ? ControlState.Hot : this.Focused ? ControlState.Focused : ControlState.Normal;
                if (this.MouseEnter != null)
                    this.MouseEnter(this, e);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnMouseLeave(EventArgs e)
        {
            if (this.Enabled)
            {
                this.mouseIn = false;
                this.State = this.Focused ? ControlState.Focused : ControlState.Normal;
                if (this.MouseLeave != null)
                    this.MouseLeave(this, e);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnMouseDown(MouseEventArgs e)
        {
            if (this.Enabled)
            {
                this.State = ControlState.Pressed;
                if (this.MouseDown != null)
                    this.MouseDown(this, e);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnMouseUp(MouseEventArgs e)
        {
            if (this.Enabled)
            {
                this.State = this.Focused ? ControlState.Focused : ControlState.Normal;
                if (this.MouseUp != null)
                    this.MouseUp(this, e);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void OnMouseMove(MouseEventArgs e)
        {
            if (this.Enabled)
            {
                this.state = this.mousePressed ? ControlState.Pressed : ControlState.Hot;
                if (this.MouseMove != null)
                    this.MouseMove(this, e);
            }
        }

        #endregion

        #region Exposed Methods

        public abstract void Draw(Graphics graphics);

        public virtual bool HitTest(Point pt)
        {
            return this.Bounds.Contains(pt);
        }

        #endregion

    }

}
